package com.ruoyi.yljf.service.impl;

import java.util.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.yljf.domain.*;
import com.ruoyi.yljf.domain.dto.*;
import com.ruoyi.yljf.domain.vo.*;
import com.ruoyi.yljf.mapper.*;
import com.ruoyi.yljf.service.*;
import com.ruoyi.yljf.domain.enums.yljfEnums;
import com.ruoyi.yljf.util.NoticeMapperFactory;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 笔记Service业务层处理
 *
 * @author metaee
 * @date 2025-01-04
 */
@Service
public class NoticeServiceImpl extends ServiceImpl<NoticeMapper, Notice> implements INoticeService {
    @Resource
    private NoticeMapper noticeMapper;

    @Resource
    private ICommentService commentService;

    @Resource
    private TokenService tokenService;

    @Resource
    public  StringRedisTemplate stringRedisTemplate;

    @Resource
    private IUserService userService;

    @Resource
    private ICourseService courseService;

    @Resource
    private final NoticeMapperFactory noticeMapperFactory;

    @Resource
    private NoticeLikeMapper noticeLikeMapper;

    @Autowired
    public NoticeServiceImpl(NoticeMapperFactory noticeMapperFactory) {
        this.noticeMapperFactory = noticeMapperFactory;
    }

    /**
     * 查询笔记列表
     *
     * @param notice 笔记
     * @return 笔记
     */
    @Override
    public List<Notice> selectNoticeList(Notice notice) {
        LambdaQueryWrapper<Notice> queryWrapper = Wrappers.lambdaQuery();
        if (StringUtils.isNotNull(notice.getUserId())) {
            queryWrapper.eq(Notice::getUserId, notice.getUserId());
        }
        if (StringUtils.isNotEmpty(notice.getNoticeType())) {
            queryWrapper.eq(Notice::getNoticeType, notice.getNoticeType());
        }
        if (StringUtils.isNotEmpty(notice.getNoticeContent())) {
            queryWrapper.eq(Notice::getNoticeContent, notice.getNoticeContent());
        }
        if (StringUtils.isNotNull(notice.getContentId())) {
            queryWrapper.eq(Notice::getContentId, notice.getContentId());
        }
        if (StringUtils.isNotNull(notice.getContentPos())) {
            queryWrapper.eq(Notice::getContentPos, notice.getContentPos());
        }
        if (StringUtils.isNotNull(notice.getLikes())) {
            queryWrapper.eq(Notice::getLikes, notice.getLikes());
        }
        if (StringUtils.isNotEmpty(notice.getOpen())) {
            queryWrapper.eq(Notice::getOpen, notice.getOpen());
        }
        if (StringUtils.isNotNull(notice.getCreatTime())) {
            queryWrapper.eq(Notice::getCreatTime, notice.getCreatTime());
        }
        if (StringUtils.isNotNull(notice.getCreatTime())) {
            queryWrapper.eq(Notice::getCreatTime, notice.getCreatTime());
        }
        return noticeMapper.selectList(queryWrapper);
    }

    /**
     * 查询课程笔记列表
     * @return 课程笔记集合
     */
    @Override
    public List<CourseNotice>  getNoticeList( Long contentId,
                                         Long contentPos,
                                         String orderBy ) {
        LambdaQueryWrapper<CourseNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseNotice::getCurId, contentId);
        queryWrapper.eq(CourseNotice::getContentPos, contentPos);

        if(orderBy==null){
            queryWrapper.eq(CourseNotice::getUserId, SecurityUtils.getUserId());
        }else {
            if(orderBy.equals("likes desc")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),false,CourseNotice::getLikes);
            }else if(orderBy.equals("likes")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),true,CourseNotice::getLikes);
            }else if(orderBy.equals("create_time desc")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),false,CourseNotice::getCreatTime);
            }else if(orderBy.equals("create_time")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),true,CourseNotice::getCreatTime);
            }
            queryWrapper.eq(CourseNotice::getOpen, "Y");
        }
        CourseNoticeMapper mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_COURSE.getDesc());
        List<CourseNotice> courseNotices = mapper.selectList(queryWrapper);
        if(orderBy == null){
            for (CourseNotice c:courseNotices
                 ) {
                Long userId = SecurityUtils.getUserId();
                // 2.判断当前登录用户是否已经点赞
                c.setIsLiked(isLiked(yljfEnums.NOTICE_TYPE_COURSE.getCode(), c.getId(),userId));
            }
        }
        return  courseNotices;
    }

    /**
     * 查询笔记列表
     * @return 笔记集合
     */
    public List  getNoticeList( Long curId,
                                String noticeType,
                                String orderBy ) {
        TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), CommonNotice.class);
        LambdaQueryWrapper<CommonNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CommonNotice::getCurId, curId);

        if(orderBy==null){
            queryWrapper.eq(CommonNotice::getUserId, SecurityUtils.getUserId());
        }else {
            if(orderBy.equals("likes desc")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),false,CommonNotice::getLikes);
            }else if(orderBy.equals("likes")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),true,CommonNotice::getLikes);
            }else if(orderBy.equals("create_time desc")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),false,CommonNotice::getCreatTime);
            }else if(orderBy.equals("create_time")){
                queryWrapper.orderBy(StrUtil.isNotBlank(orderBy),true,CommonNotice::getCreatTime);
            }
            queryWrapper.eq(CommonNotice::getOpen, "Y");
        }
        BaseMapper<CommonNotice> mapper = noticeMapperFactory.getMapper(noticeType);
        List<CommonNotice> commonNotices = mapper.selectList(queryWrapper);
        return  commonNotices;
    }

    /**
     * 根据 id 查询笔记详情
     * @param id
     * @return
     */
    @Override
    public NoticeDetailVO getById(Long id, String noticeType, HttpServletRequest req) {
        BaseMapper<?> mapper = noticeMapperFactory.getMapper(noticeType);
        NoticeDetailVO noticeDetailVO = BeanUtil.copyProperties(mapper.selectById(id), NoticeDetailVO.class);
        noticeDetailVO.setNoticeType(noticeType);
        LoginUser loginUser = tokenService.getLoginUser(req);
        if (loginUser == null) {
            // 用户未登录，无需查询是否点赞
            return noticeDetailVO;
        }
        Long userId = loginUser.getUserId();
        noticeDetailVO.setLiked(isLiked(noticeDetailVO.getNoticeType(),noticeDetailVO.getId(),userId));
        return noticeDetailVO;
    }

    /**
     * 添加课程笔记
     * @param noticeDTO
     * @return
     */
    @Override
    @Transactional
    public Integer addNotice(NoticeDTO noticeDTO) {
        User user = userService.getById(SecurityUtils.getUserId());
        Course course = courseService.getById(noticeDTO.getContentId());
        CourseNotice notice = new CourseNotice();
        BeanUtils.copyProperties(noticeDTO,notice);
        notice.setCurId(course.getId());
        notice.setUserId(user.getUserId());
        notice.setUserName(user.getUserName());
        notice.setAvatar(user.getAvatar());
        notice.setName(course.getName());
        if(noticeDTO.getSycCom().equals("Y")){
            CommentAddDTO comment = new CommentAddDTO();
            comment.setContent(notice.getNoticeContent());
            comment.setPostId(notice.getCurId());
            comment.setPostType(yljfEnums.COURSE.getCode());
            commentService.commentAdd(comment);
        }

        CourseNoticeMapper mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_COURSE.desc());
        return mapper.insert(notice);
    }

    /**
     * 添加医案/经方/药材笔记
     * @param noticeDTO
     * @return
     */
    @Override
    @Transactional
    public Integer addNoticeV2(NoticeDTO2 noticeDTO) {
        BaseMapper<CommonNotice> mapper = noticeMapperFactory.getMapper(noticeDTO.getNoticeType());
        User user = userService.getById(SecurityUtils.getUserId());
        CommonNotice notice = new CommonNotice();
        BeanUtils.copyProperties(noticeDTO,notice);
        notice.setCurId(noticeDTO.getCurId());
        notice.setUserId(user.getUserId());
        notice.setUserName(user.getUserName());
        notice.setAvatar(user.getAvatar());
        notice.setName(noticeDTO.getName());
        if(noticeDTO.getSycCom().equals("Y")){
            CommentAddDTO comment = new CommentAddDTO();
            comment.setContent(notice.getNoticeContent());
            comment.setPostId(notice.getCurId());
            comment.setPostType(noticeDTO.getNoticeType());
            commentService.commentAdd(comment);
        }
        return mapper.insert(notice);
    }


    @Override
    public List<CourseNotice> getCourseNotice() {
        LambdaQueryWrapper<CourseNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseNotice::getOpen, "Y");
        BaseMapper<CourseNotice> mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_COURSE.getDesc());
        return mapper.selectList(queryWrapper);
    }

    @Override
    public List<DrugNotice> getDrugNotice() {
        LambdaQueryWrapper<DrugNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrugNotice::getOpen, "Y");
        BaseMapper<DrugNotice> mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_DRUG.getDesc());
        return mapper.selectList(queryWrapper);
    }

    @Override
    public List<MedicalNotice> getMedicalNotice() {
        LambdaQueryWrapper<MedicalNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MedicalNotice::getOpen, "Y");
        BaseMapper<MedicalNotice> mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_MEDIAL.getDesc());
        return mapper.selectList(queryWrapper);
    }

    @Override
    public List<JingfangNotice> getJingfangNotice() {
        LambdaQueryWrapper<JingfangNotice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(JingfangNotice::getOpen, "Y");
        BaseMapper<JingfangNotice> mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_JINGFANG.getDesc());
        return mapper.selectList(queryWrapper);
    }

    @NotNull
    @Transactional
    public Integer pointLike(Long noticeId, Long userId, String noticeType) {
        noticeType = getNoticeType(noticeType);
        // redis功能key + noticeType + ":" + noticeId
        String noticeLikedKey = CacheConstants.NOTICE_LIKED_KEY + noticeType+":"+noticeId;
        Boolean isLiked = isLiked(noticeType,noticeId, userId);
        if(Boolean.TRUE.equals(isLiked)){
            // 如果已点赞，取消点赞
            // 数据库笔记点赞数 -1
            undoLike(noticeType,noticeId, userId);
            // 把用户从Redis的set集合移除
            stringRedisTemplate.opsForSet().remove(noticeLikedKey, String.valueOf(userId));
            return 0;
        }else{
            // 如果未点赞，可以点赞
            // 数据库笔记点赞数 + 1
            like(noticeType,noticeId, userId);
            // 保存用户到Redis的set集合
            stringRedisTemplate.opsForSet().add(noticeLikedKey, String.valueOf(userId));
            return 1;
        }
    }

    @Override
    @Transactional
    public Integer saveNotice(Long noticeId) {
        CourseNoticeMapper mapper = noticeMapperFactory.getMapper(yljfEnums.NOTICE_TYPE_COURSE.desc());
        CourseNotice courseNotice = mapper.selectContentById(noticeId);
        NoticeDTO noticeDTO = new NoticeDTO();
        noticeDTO.setNoticeContent(courseNotice.getNoticeContent());
        noticeDTO.setContentPos(courseNotice.getContentPos());
        noticeDTO.setContentId(courseNotice.getCurId());
        noticeDTO.setOpen("N");
        noticeDTO.setSycCom("N");
        return addNotice(noticeDTO);
    }

    @Override
    public Integer saveNoticeV2(Long id) {
        return null;
    }

    /**
     * 判断用户是否已经点赞：
     *         已经点赞：笔记点赞存在记录
     *         未点赞：笔记点赞不存在记录
     * @param noticeType：笔记类型
     * @param noticeId：笔记id
     * @param userId：点赞用户id
     * @return
     */
    public boolean isLiked(String noticeType,Long noticeId, Long userId) {
        // 2.判断当前登录用户是否已经点赞
        String key = CacheConstants.NOTICE_LIKED_KEY + noticeType+":"+noticeId;
        boolean is = Boolean.TRUE.equals(stringRedisTemplate.opsForSet().isMember(key, userId.toString()));
        if(!is){
            // 查数据库点赞记录
            LambdaQueryWrapper<NoticeLike> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(NoticeLike::getUserId, userId)   // 这里是点赞用户id
                    .eq(NoticeLike::getNoticeId, noticeId)
                    .eq(NoticeLike::getType, noticeType);
            Long aLong = noticeLikeMapper.selectCount(wrapper);
            if(aLong != 0) {  // 数据库中已经点赞了，将点赞在Redis中标记
                stringRedisTemplate.opsForSet().add(key, userId.toString());
            } else {  // 数据库该用户也未点赞，直接返回未点赞
                return false;
            }
        }
        return is;
    }


    /**
     * 笔记点赞：添加用户点赞特定笔记记录
     * @param type：笔记类型
     * @param noticeId：笔记id（通过type才嫩确定在某张笔记表中）
     * @param userId：点赞用户id
     * @return
     */
    public void like(String type,Long noticeId, Long userId) {
        // 新建用户笔记点赞记录
        NoticeLike noticeLike = new NoticeLike();
        noticeLike.setNoticeId(noticeId);
        noticeLike.setType(type);
        noticeLike.setUserId(userId);
        noticeLikeMapper.insert(noticeLike);
        // 笔记点赞数 + 1
        CommonNoticeMapper mapper = noticeMapperFactory.getMapper(yljfEnums.descOfCode(type));
        mapper.like(noticeId);
    }

    /**
     * 取消用户笔记点赞：删除用户笔记点赞记录
     * @param type：笔记类型
     * @param noticeId：笔记id
     * @param userId：点赞用户id
     * @return
     */
    public void undoLike(String type,Long noticeId, Long userId) {
        LambdaQueryWrapper<NoticeLike> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(NoticeLike::getUserId, userId)
                .eq(NoticeLike::getNoticeId, noticeId)
                .eq(NoticeLike::getType, type);
        noticeLikeMapper.delete(wrapper);
        // 笔记点赞数 - 1
        CommonNoticeMapper mapper = noticeMapperFactory.getMapper(yljfEnums.descOfCode(type));
        mapper.undoLike(noticeId);
    }

    public String getNoticeType(String type) {
        switch (type) {
            case "药材":
                return "drug";
            case "课程":
                return "course";
            case "经方":
                return "jingfang";
            case "医案":
                return "medical";
            default:
                throw new IllegalArgumentException("Unknown type: " + type);
        }
    }
}
